package com.kingbook.core.annotations;

import com.kingbook.common.utils.NumberUtils;
import com.kingbook.core.enums.ResultCode;
import com.kingbook.core.result.JSONPageResult;
import com.kingbook.core.result.JSONResult;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import java.util.Map;

import static com.kingbook.core.enums.ResultCode.FAILED;
import static java.lang.Integer.MIN_VALUE;

/**
 * @Author: Bucky
 * @Date: 2019/1/2
 * @Version 1.0
 */

@Aspect
@Component
public class ContainPropertiesAspect {

    private static Logger logger = LoggerFactory.getLogger(ContainPropertiesAspect.class);

    @Around("@annotation(cp)")
    private Object processValidate(ProceedingJoinPoint pjp, ContainProperties cp) throws Throwable {
        String[] properties = cp.value();
        PropertieVerify[] verifies = cp.properties();
        Object[] obj = pjp.getArgs();
        Signature signature = pjp.getSignature();
        String method = signature.toString();
        for (Object o : obj) {
            if (o instanceof Map) {
                Map<?, ?> map = (Map<?, ?>) o;
                if (properties.length > 0) {
                    for (String key : properties) {
                        if (!map.containsKey(key)) {
                            logger.error("----> ContainProperties process: {} Map->{}缺少参数:{}] properties:{} args:{} ", method, cp.mapName(), key, properties, obj);
                            return failed(signature, FAILED, "缺少参数[" + key + "]");
                        }
                    }
                } else if (verifies.length > 0) {
                    for (PropertieVerify v : verifies) {
                        if (!map.containsKey(v.name())) {
                            logger.error("----> ContainProperties process: {} Map->{}缺少参数:{}] properties:{} args:{} ", method, cp.mapName(), v.name(), properties, obj);
                            return failed(signature, FAILED, "缺少参数[" + v.name() + "]");
                        } else {
                            int minValue = v.minValue();
                            int maxValue = v.maxValue();
                            int minLength = v.minLength();
                            int maxLength = v.maxLength();
                            Object p = map.get(v.name());
                            if (p == null)
                                return failed(signature, FAILED, "参数[" + v.name() + "]值为null");
                            String str = p.toString();
                            if (minLength != MIN_VALUE && str.length() < minLength) {
                                return failed(signature, FAILED, "参数[" + v.name() + "]长度不能小于" + minLength);
                            }
                            if (maxLength != MIN_VALUE && str.length() > maxLength) {
                                return failed(signature, FAILED, "参数[" + v.name() + "]长度不能大于" + maxLength);
                            }
                            if (minValue != MIN_VALUE) {
                                if (!NumberUtils.isNumeric(str))
                                    return failed(signature, FAILED, "参数[" + v.name() + "]非数字");
                                if (Long.parseLong(str) < minValue)
                                    return failed(signature, FAILED, "参数[" + v.name() + "]值不能小于" + minValue);
                            }
                            if (maxValue != MIN_VALUE) {
                                if (!NumberUtils.isNumeric(str))
                                    return failed(signature, FAILED, "参数[" + v.name() + "]非数字");
                                if (Long.parseLong(str) > maxValue)
                                    return failed(signature, FAILED, "参数[" + v.name() + "]值不能大于" + maxValue);
                            }
                        }
                    }
                }
            }
        }

        return pjp.proceed();
    }

    private Object failed(Signature signature, ResultCode code, String msg) {
        Class<?> returnType = ((MethodSignature) signature).getReturnType();
        if (JSONPageResult.class.getName().equals(returnType.getTypeName()))
            return JSONPageResult.failed(code, msg);
        return JSONResult.failed(code, msg);
    }
}
